﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Linq;
using Framework.Domain.DomainObject;
using Framework.Domain.DomainObject.Bo;
using Framework.Domain.Interface.DomainObject.UnitOfWork;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using System.ComponentModel.DataAnnotations.Schema;
using Framework.Commons.FileHelper;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Debug;

namespace Framework.Domain.UnitOfWork
{
    public class AppUnitOfWork : DbContext, IAppUnitOfWork
    {
        string userName = "乔安生";

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //注入Sql链接字符串
            optionsBuilder.UseSqlServer(@"Database=DDD;User ID=sa;Password=111111;Server=.;");
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseLoggerFactory(LoggerFactory);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            Type type = null;
            try
            {
                //List<CompilationLibrary> compilationLibrary = DependencyContext
                //    .Default
                //    .CompileLibraries
                //    .Where(x => !x.Serviceable && x.Type != "package").ToList();

                List<string> dllList = new List<string>()
                {
                    "Framework.Commons",
                    "Framework.Domain",
                    "Framework.Domain.Interface",
                    "Application.Services",
                    "Application.Services.Dto",
                    "Application.Services.Interface",
                    "Domain.Interface",
                    "Domain.Organization",
                    "Repository.Interface",
                    "Repository.Organization",
                };

                foreach (var _compilation in dllList)
                {
                    string assemblyPath = AppContext.BaseDirectory + _compilation + ".dll";

                    AssemblyLoadContext.Default
                    .LoadFromAssemblyPath(assemblyPath)
                    //.LoadFromAssemblyName(new AssemblyName(assemblyPath))
                    .GetTypes()
                    .Where(x => x.GetTypeInfo().BaseType != null && x.BaseType == (typeof(BaseBoEntity)))
                    .ToList().ForEach(t =>
                    {
                        type = t;
                        modelBuilder.Model.AddEntityType(t);
                    });
                }
                base.OnModelCreating(modelBuilder);
            }
            catch (Exception ex)
            {

            }
        }

        public void AttachRemove<TEntity>(TEntity item) where TEntity : class
        {
            base.Entry<TEntity>(item).State = EntityState.Deleted;
        }

        public DbSet<TEntity> CreateSet<TEntity>()
            where TEntity : class
        {
            return base.Set<TEntity>();
        }

        public new int SaveChanges()
        {
            //是否记录EF变更日志
            bool efLogFlag = true;
            if (efLogFlag)
            {
                WriteEFDataLog();
            }

            return base.SaveChanges();
        }



        #region EF变更日志
        /// <summary>
        /// EF变更日志
        /// </summary>
        private void WriteEFDataLog()
        {
            //获取到EF变更条目
            var list = this.ChangeTracker.Entries();
            foreach (var item in list)
            {
                //对应的表名
                string tableName = "";

                #region 获取表名
                Type type = item.Entity.GetType();
                Type patientMngAttrType = typeof(TableAttribute);
                TableAttribute attribute = null;
                if (type.IsDefined(patientMngAttrType, true))
                {
                    attribute = type.GetCustomAttributes(patientMngAttrType, true).FirstOrDefault() as TableAttribute;
                    if (attribute != null)
                    {
                        tableName = attribute.Name;
                    }
                }

                if (string.IsNullOrEmpty(tableName))
                {
                    tableName = type.Name;
                }
                #endregion

                switch (item.State)
                {
                    case EntityState.Detached:

                        break;
                    case EntityState.Unchanged:

                        break;
                    case EntityState.Deleted:

                        break;
                    case EntityState.Modified:
                        WriteEFUpdateLog(item, tableName);
                        break;
                    case EntityState.Added:

                        break;
                }
            }
        }

        /// <summary>
        /// 记录EF修改操作日志
        /// </summary>
        /// <param name="entry"></param>
        /// <param name="tableName"></param>
        private void WriteEFUpdateLog(EntityEntry entry, string tableName)
        {
            var propertyList = entry.CurrentValues.Properties.Where(i => entry.Property(i.Name).IsModified);

            PropertyEntry keyEntity = entry.Property("KeyId");
            foreach (var prop in propertyList)
            {
                PropertyEntry entity = entry.Property(prop.Name);
                string log = $"用户：{ userName }，对表：{ tableName } 进行了修改，原始值：{ entity.OriginalValue }，当前值：{  entity.CurrentValue }, 唯一标识：{ keyEntity.CurrentValue }";
                WriteLog(log, EntityState.Modified);
            }
        }

        private void WriteLog(string log, EntityState state)
        {
            string logPath = AppContext.BaseDirectory + "EFLog.txt";
            FileStreamHelper.AppendAllLineText(logPath, $"{ state }: 创建时间：{ DateTime.Now } 日志内容： { log }");
        }

        #endregion


        public static readonly LoggerFactory LoggerFactory =
             new LoggerFactory(new[] { new DebugLoggerProvider() });


    }
}
